package org.rsbot.script.util;

import org.rsbot.script.methods.MethodContext;
import org.rsbot.script.methods.MethodProvider;
import org.rsbot.script.methods.Skills;

/**
 * Skill data tracker
 *
 * @author Timer
 * @author Hyperion
 */
public class SkillData extends MethodProvider {
    private final int[] startExp = new int[25], startLvl = new int[25];
    private Timer runTimer = null;

    public SkillData(final MethodContext ctx, final Timer runTimer) {
        super(ctx);
        this.runTimer = runTimer;
        for (int i = 0; i < startExp.length; i++) {
            startExp[i] = exp(i);
        }
        for (int i = 0; i < startLvl.length; i++) {
            startLvl[i] = level(i);
        }
    }

    public SkillData(final MethodContext ctx) {
        this(ctx, new Timer(0));
    }

    public int level(final int idx) {
        return methods.skills.getCurrentLevel(idx);
    }

    public int exp(final int idx) {
        return methods.skills.getCurrentExp(idx);
    }

    public int levelsGained(final int idx) {
        return level(idx) - startLvl[idx];
    }

    public int expGain(final int idx) {
        return exp(idx) - startExp[idx];
    }

    public int expToLevel(final int idx) {
        return expToLevel(idx, level(idx) + 1);
    }

    public int expToLevel(final int idx, final int lvl) {
        if (lvl < 1 || methods.skills.getMaxLevel(idx) < lvl) {
            return -1;
        }
        return Skills.XP_TABLE[lvl] - exp(idx);
    }

    public double percentToLevel(final int idx) {
        return percentToLevel(idx, level(idx) + 1);
    }

    public double percentToLevel(final int idx, final int lvl) {
        int curLvl = level(idx);
        final int maxLevel = methods.skills.getMaxLevel(idx);
        if (lvl < 1 || lvl > maxLevel) {
            return 0;
        }
        if (curLvl == maxLevel || curLvl == lvl) {
            return 100;
        }
        return ((100 * (exp(idx) - Skills.XP_TABLE[curLvl])) / (Skills.XP_TABLE[lvl] - Skills.XP_TABLE[curLvl]));
    }

    public static double hourly(int total, long time) {
        return (total * 3600000D / time);
    }

    public double hourlyExp(final int idx) {
        return hourly(expGain(idx), runTimer.getElapsed());
    }

    public long timeToLevel(final int idx) {
        double hourlyExp = hourlyExp(idx);
        if (hourlyExp == 0) {
            return 0;
        }
        return 1000 * (long) ((expToLevel(idx) * 3600) / hourlyExp);
    }

    public long timeToLevel(final int idx, final int level) {
        double hourlyExp = hourlyExp(idx);
        if (hourlyExp == 0) {
            return 0;
        }
        return 1000 * (long) ((expToLevel(idx, level) * 3600) / hourlyExp);
    }

    public int[] getStartExp() {
        return startExp;
    }

    public int[] getExp() {
        final int[] a = new int[startExp.length];
        for (int i = 0; i < a.length; i++) {
            a[i] = exp(i);
        }
        return a;
    }
}
